#include "stdafx.h"
#include "NeuralNet.h"
#include <cmath>


NeuralNet::NeuralNet(size_t inCount, const std::vector<size_t>& layersSize)
: inCount(inCount), layersSize(layersSize)
{
	layersCount = layersSize.size();
	layersIn.resize(layersCount);
	layersOut.resize(layersCount);
	layersWeight.resize(layersCount);
	layersInCount.resize(layersCount);

	for(size_t i = 0; i < layersCount; i++)
	{
		layersOut[i].resize(layersSize[i]);
		if(i == 0)
		{
			layersInCount[i] = inCount;
			layersIn[i] = 0;
		}
		else
		{
			layersInCount[i] = layersSize[i - 1];
			layersIn[i] = &layersOut[i - 1][0];
		}
	}

	size_t weightsCount = 0;
	for(size_t i = 0; i < layersCount; i++)
	{
		weightsCount += layersSize[i] * (layersInCount[i] + 1);
	}
	weights.resize(weightsCount);



	float* weightsPtr = &weights[0];
	for(size_t i = 0; i < layersCount; i++)
	{
		layersWeight[i] = weightsPtr;
		weightsPtr += layersSize[i] * (layersInCount[i] + 1);
	}
}

size_t NeuralNet::getWeightsCount() const
{
	return weights.size();
}

float* NeuralNet::getWeights()
{
	return &weights[0];
}

float* NeuralNet::run(float* in)
{
	layersIn[0] = in;
	calc();
	return &layersOut[layersCount - 1][0];
}

static inline float F(float x)
{
	return 2.f/(1.f + exp(-x)) - 1.f;
}

void NeuralNet::calc()
{
	for(size_t i = 0; i < layersCount; i++)
	{
		size_t size = layersSize[i];
		size_t inCount = layersInCount[i];
		float* in = layersIn[i];
		float* out = &layersOut[i][0];
		for(size_t j = 0; j < size; j++)
		{
			float sum = 0.f;
			float* w = &layersWeight[i][j*(inCount + 1)];
			for(size_t k = 0; k < inCount; k++)
			{
				sum += in[k]*w[k];
			}
			sum += w[inCount];
			out[j] = F(sum);
		}
	}
}